import pandas as pd
import requests

from app.main.dao.performance_prediction_imitate_dao import PerformancePredirtionImitateDao
from app.main.entity.performance_prediction_imitate_entity  import PerformancePredirtionImitateEntity
from app.util.result import Result
from app.util.get_static_path import get_group_path,get_nogroup_path
from app.util.data_clean.outlier_missing import OutlierMissing
# from app.util.get_static_path import get_path
import pickle
import numpy as np
import os
import sklearn.model_selection as ms
from sklearn import metrics
import copy
from sklearn.metrics import mean_squared_error
from sklearn.metrics import r2_score
from datetime import datetime
from sklearn.metrics import roc_auc_score,roc_curve,auc


class PerformancePredirtionImitate:

    def cout1(self,pred, y_test,upper_error,lower_error):  # 相对误差命中率
        count = 0
        for i in range(len(y_test)):
            # if y_test[i] != 0:
            if pred[i] <= y_test[i] + upper_error and pred[i] >= y_test[i] + lower_error:
                count += 1
        # else:
        #     continue
        if len(y_test) == 0:
            return  Result.error(msg="请检查数据集")
        return count / len(y_test)

    def rmsle(self,y, y_pred):
        return np.sqrt(mean_squared_error(y, y_pred))
    def data_clean(self,data,input_list,model_msg,column_list):
        data = data.fillna(value=np.NaN)
        data.replace(" ",np.nan,inplace = True)
        data = data.apply(pd.to_numeric, errors='ignore')
        # cols_with_letters = data.select_dtypes(include='object').columns.tolist()
        # # 除了input_list.reel_key以外，删除所有带有字母的列
        # cols_to_drop = [col for col in cols_with_letters if col != model_msg[0]['reel_key'] and col not in column_list]
        # data = data.drop(cols_to_drop, axis=1)
        # data = OutlierMissing.remove_all_nan_columns(data)
        # a = data.shape
        # if len(data) > 1:
        #     data = OutlierMissing.remove_same_value_columns(data,input_list)
        # data = OutlierMissing.remove_nan_percentage_columns(data, 0.05)
        # data = OutlierMissing.remove_nan_percentage_rows(data, 0.05)

        for column_name, column_data in data.items():
            if column_name == model_msg[0]['reel_key'] or column_name == 'SG_SMALL_CLASS' or column_name == '屈服强度Rp0.2真实值' or column_name =='INSERT_TIME':
                continue
            if column_name == model_msg[0]['reel_key'] or column_name == 'sg_small_class' or column_name == 'insert_time':
                continue
            # if data[column_name].isnull().values.any():
            #     data[column_name] = data[column_name].fillna(data[column_name].mean())
            data[column_name] = data[column_name].astype(float).round(6)
        # nan_values = data.isnull().values.any()
        # inf_values = not np.isfinite(data.values).all()
        return data
    def performance_imitate(self,request_data):
        time = datetime.now()
        #输入参数类处理
        input_list = PerformancePredirtionImitateEntity(request_data)
        # data = PerformancePredirtionEvaLuationDao().select_evaluation_data(request_data)  # 数据库操作示例
        # print((datetime.now()-time).total_seconds())
        if input_list.data == [] :
            return Result.error(msg = "{}表中在{}至{}之间数据查询为空".format(input_list.tablename,input_list.begin_data,input_list.end_data))
        elif input_list.data is None:
            return Result.error(msg="{}表中在{}至{}之间数据查询失败，请检查参数".format(input_list.tablename, input_list.begin_data, input_list.end_data))
        column_list = input_list.column.split(',')
        data = pd.DataFrame(input_list.data, columns=column_list)
        # data = data[data[model_msg[0]['y']] != 0]
        # # 数据清洗
        # data = PerformancePredirtionEvaluation().data_clean(data, input_list)
        # 样本集特征
        # 绝对误差分别对应'屈服强度Rp0.2', '抗拉强度Rm', '断后伸长率A'
        index = [15, 15, 2]
        # 相对误差，分别对应'屈服强度Rp0.2', '抗拉强度Rm', '断后伸长率A'
        index1 = [8, 8, 5]
        # head = [model_msg[0]['y']]  # 三个指标
        # X = data.iloc[:, :-2]  # 输入特征
        # Y = data.iloc[:, -2:-1]  # 输出特征：'屈服强度Rp0.2', '抗拉强度Rm', '断后伸长率A'
        # 指标
        l = 5
        # for file_name in os.listdir('app/train'):
        #     if input_list.modelname in file_name:
        #         folder_path = get_path(file_name)
        # try:
        #     with open(folder_path, "rb") as f:
        #         model = pickle.load(f)
        # except:
        #     return Result.error(msg = "模型不存在，请调用训练模型接口生成模型")
        result_list = []
        result_group_list = []
        value_dict = dict()
        if input_list.group_var == '':
            model_msg = PerformancePredirtionImitateDao().select_feature_colunms_nogroup(input_list.modelname)
            if model_msg == [] or model_msg[0]['y'] is None:
                return Result.error(msg="请重新训练模型")
            model_zj = PerformancePredirtionImitateDao().select_train_time(input_list.modelname)
            model_time = model_zj[0]['training_time'].replace("-", "_").replace(" ", "_").replace(":", "_")
            model_name = model_zj[0]['model_name'] + '_' + model_time + '.pkl'
            for model in model_msg:
                model_n = model['model_load'].split("\\")[-1]
                if model_n == model_name:
                    model_msg = [model]
                    break
            upper_error = float(model_msg[0]['upper_error'])
            lower_error = float(model_msg[0]['lower_error'])
            colunms = model_msg[0]['model_feature'].split(",")
            X = data.drop(labels = [model_msg[0]['y'].lower()],axis = 1,inplace = False)
            Y = data.loc[:, model_msg[0]['y']]
            X_test = data.loc[:, colunms]
            X_test = PerformancePredirtionImitate().data_clean(X_test, input_list, model_msg, column_list)

            for file_name in os.listdir('app/train/no_group_file'):
                if model_name == file_name:
                    folder_path = get_nogroup_path(file_name)
            try:
                with open(folder_path, "rb") as f:
                    model = pickle.load(f)
            except:
                return Result.error(msg="请重新训练模型")
            pred_y_XGB = model.predict(X_test)
            # print ("rmsle:",self.rmsle(y_test,pred_y_XGB))
            Y = Y.to_numpy()
            Y = np.where(Y == 0, 1e-8, Y)  # 将Y中的0替换为1e-8或其他非零小值
            y1 = pred_y_XGB.tolist()
            y2 = Y.tolist()
            new_list = []
            for item in y2:
                if isinstance(item, str):
                    try:
                        item = float(item)
                    except ValueError:
                        pass
                new_list.append(item)
            y2 = new_list
            # 保存到表格
            X[f"Y_true"] = y2
            X[f"Y_pre"] = y1
            X[f"Y_error"] = abs(X[f"Y_pre"] - X[f"Y_true"])
            y = X[f"Y_true"]
            for key, value in X[[model_msg[0]['reel_key'], 'Y_true', 'Y_pre', 'Y_error']].iterrows():
                value = value.to_dict()
                value_dict['Y'] = model_msg[0]['y']
                value_dict['Y_true'] = int(value['Y_true'])
                value_dict['Y_pre'] = int(value['Y_pre'])
                value_dict['Y_error'] = abs(value_dict['Y_true'] - value_dict['Y_pre'])
                if type(value[model_msg[0]['reel_key']]) is str:
                    value_dict[model_msg[0]['reel_key']] = value[model_msg[0]['reel_key']]
                else:
                    value_dict[model_msg[0]['reel_key']] = str(int(value[model_msg[0]['reel_key']]))
                value_dict['group_var'] = input_list.group_var
                value_dict['group_var_val'] = ''
                value_dict['Y'] = model_msg[0]['y']
                result_list.append(copy.deepcopy(value_dict))
        # 结果保存
        else:
            Y_true = []
            Y_pre = []
            data_grby = data.groupby(input_list.group_var)
            model_msg = PerformancePredirtionImitateDao().select_feature_colunms_group(input_list.modelname)
            if model_msg == []:
                return Result.error(msg="请重新训练模型")
            model_zj = PerformancePredirtionImitateDao().select_train_time(input_list.modelname)
            model_time = model_zj[0]['training_time'].replace("-", "_").replace(" ", "_").replace(":", "_")
            model_name = model_zj[0]['model_name'] + '_' + model_time + '.pkl'
            for model in model_msg:
                model_n = model['model_load'].split("\\")[-1]
                if model_n == model_name:
                    model_msg = [model]
                    break
            upper_error = float(model_msg[0]['upper_error'])
            lower_error = float(model_msg[0]['lower_error'])
            for grby_x, grby_y in data_grby:
                model_state = 0
                for model_m in model_msg:
                    if model_m['y'] is None:
                        return Result.error(msg="请重新训练模型")
                    if str(model_m['group_var_val']) == str(grby_x) and str(model_m['group_var']) == str(input_list.group_var):
                        colunms = model_m['model_feature'].split(",")
                        X_test = grby_y.loc[:, colunms]
                        X = grby_y.drop(labels=[model_msg[0]['y'].lower()], axis=1,
                                        inplace=False)
                        Y = grby_y.loc[:, model_msg[0]['y']]
                        X_test = PerformancePredirtionImitate().data_clean(X_test, input_list, model_msg, colunms)
                        for file_name in os.listdir('app/train/group_file'):
                            if model_name == file_name:
                                folder_path = get_group_path(file_name)
                                model_state = 1
                                break
                        try:
                            with open(folder_path, "rb") as f:
                                model = pickle.load(f)
                                break
                        except:
                            return Result.error(msg="请重新训练模型")
                if model_state == 0:
                    result_group_list = []
                    for key, value in grby_y[[input_list.reel_key, input_list.group_var,input_list.Y]].iterrows():
                        value = value.to_dict()
                        value_dict['Y'] = input_list.Y
                        value_dict['Y_true'] = value[input_list.Y]
                        value_dict['Y_pre'] = ''
                        value_dict['Y_error'] = ''
                        value_dict['train_state'] = model_state
                        # if type(value[input_list.reel_key]) is str:
                        value_dict[input_list.reel_key] = value[input_list.reel_key]
                        # else:
                        #     value_dict[model_msg[0]['reel_key']] = str(int(value[model_msg[0]['reel_key']]))
                        value_dict['group_var'] = input_list.group_var
                        value_dict['group_var_val'] = value[input_list.group_var]
                        del value[input_list.group_var]
                        result_group_list.append(copy.deepcopy(value_dict))
                else:
                    pred_y_XGB = model.predict(X_test)
                    # print ("rmsle:",self.rmsle(y_test,pred_y_XGB))
                    Y = Y.to_numpy()
                    y1 = pred_y_XGB.tolist()
                    Y_pre.extend(y1)
                    y2 = Y.tolist()
                    new_list = []
                    for item in y2:
                        if isinstance(item, str):
                            try:
                                item = float(item)
                            except ValueError:
                                pass
                        new_list.append(item)
                    y2 = new_list
                    Y_true.extend(y2)
                    # 保存到表格
                    X[f"Y_true"] = y2
                    X[f"Y_pre"] = y1
                    X[f"Y_error"] = abs(X[f"Y_pre"] - X[f"Y_true"])
                    y = X[f"Y_true"]
                    # if len(grby_y) == 1:
                    #     continue
                    result_group_list = []
                    for key, value in X[
                        [model_msg[0]['reel_key'], input_list.group_var, 'Y_true', 'Y_pre', 'Y_error']].iterrows():
                        value = value.to_dict()
                        value_dict['Y'] = model_msg[0]['y']
                        value_dict['Y_true'] = int(value['Y_true'])
                        value_dict['Y_pre'] = int(value['Y_pre'])
                        value_dict['Y_error'] = abs(value_dict['Y_true'] - value_dict['Y_pre'])
                        value_dict['train_state'] = model_state
                        if type(value[model_msg[0]['reel_key']]) is str:
                            value_dict[model_msg[0]['reel_key']] = value[model_msg[0]['reel_key']]
                        else:
                            value_dict[model_msg[0]['reel_key']] = str(int(value[model_msg[0]['reel_key']]))
                        value_dict['group_var'] = input_list.group_var
                        value_dict['group_var_val'] = value[input_list.group_var]
                        del value[input_list.group_var]
                        result_group_list.append(copy.deepcopy(value_dict))
                result_list.append(result_group_list)
            # acc = round(self.cout1(Y_pre, Y_true,upper_error,lower_error) * 100, 4)
        print((datetime.now() - time).total_seconds())
        result = {
            'result': result_list
        }
        return Result.success(data=result_list)


# 传输图片示例,将图片放到static文件夹下，调用get_path传入文件名获得绝对路径，url填写接收方接口的url
# def send_picture():
#     files = {
#         "image_file": ("demo.jpg", open(get_path('demo.jpg'), 'rb'))}
#     requests.post('http://127.0.0.1:8081/upload', files=files)

